home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Gigarom 4
/
Mac Giga-ROM 4.0 - 1993.toast
/
FILES
/
HYP
/
E-G
/
Fractal3.cpt
/
fractal2.a
< prev
next >
Wrap
Text File
|
1989-02-26
|
12KB
|
461 lines
;
; fractal xcmd v0.3 -- Doug Felt, Oct 14, 1987
;
; This draws a fractal on the screen. Not to the card, yet. Function is
; f(z) = z * z + c, julia set mapped to 4 patterns.
;
; Format:
; Fractal seed.h seed.v [res = 8 [limit = 32 [lock = 0]]]
;
; seed is the complex constant c (v imaginary)
; res is the number of pixels on a side for the point to plot
; limit is the max number of iterations (best between 16 & 128, multiple of 4),
; lower limit means most complex regions of the fractal are white
; if lock is 0, pressing the mouse will immediately stop the drawing, otherwise
; pressing the mouse has no effect and drawing can only be stopped by reboot or
; fancy macsbug work.
;
; Doug Felt, AIR/CAT Project
; duggie@jessica.stanford.edu
;
;
; To compile and link in MPW C:
;
; C -q2 Fractal.c
; link -sn Main=Fractal -sn STDIO=Fractal ∂
; -sn INTENV=Fractal -rt XCMD=104 ∂
; -m FRACTAL Fractal.c.o "{CLibraries}CRunTime.o" ∂
; -o HyperCommands
;
;
; Well now, I thought this was so neat, and Doug was right it needs a
; little more speed. So thats what I did, I rewrote the "C" program in
; assembler with direct processing on the MC68881 FPU. I think this makes
; quite a difference. The only thing is that it only runs on a MacII. It
; might run on one or more of the accelerator cards. Give it a try. If
; necessary, change the COID= parameter below if they are using other than 1.
;
; Ray Sanders
; Green Grass Software, Inc.
;
; CIS: 70277,3233 GEnie: RAYSANDERS
;
; To assemble and link with MPW:
;
; fractal2.a.o ƒ fractal2.make fractal2.a
; Asm fractal2.a -l -font Monaco,9
; fractal2 ƒ fractal2.make fractal2.a.o
; link -o fractal2 -rt XCMD=105 -sn Main=Fractal2 -t STAK -c WILD ∂
; fractal2.a.o ∂
; -o "Fractals"
;
;
fractal2 MAIN
BLANKS ON
STRING ASIS
MC68881 COID=1,PREC=X,ROUND=N
; INCLUDE 'Traps.a'
; INCLUDE 'SysEqu.a'
PRINT OFF
INCLUDE 'Traps.a'
INCLUDE 'SysEqu.a'
PRINT ON,NOWARN
; PRINT ON
; HyperCard data structure offsets
XCmdParamCount EQU 0 ;number of parameters
XCmdParams EQU 2 ;16 handles to C-strings
XCmdReturnVal EQU 66 ;handle to return string
XCmdPassFlag EQU 70 ;boolean, to pass message through
XCmdEntryPoint EQU 72 ;hyperCard call-back
XCmdRequest EQU 76 ;call back opcode field
XCmdResult EQU 78 ;call back result field
XCmdInArgs EQU 80 ;8 longs, input arguments
XCmdOutArgs EQU 112 ;4 longs, output arguments
MenuList EQU $A1C
; result codes
xresSucc EQU 0
xresFail EQU 1
xresNotImp EQU 2
; request codes
xreqSendCardMessage EQU 1
xreqEvalExpr EQU 2
xreqStringLength EQU 3
xreqStringMatch EQU 4
xreqSendHCMessage EQU 5
xreqZeroBytes EQU 6
xreqPasToZero EQU 7
xreqZeroToPas EQU 8
xreqStrToLong EQU 9
xreqStrToNum EQU 10
xreqStrToBool EQU 11
xreqStrToExt EQU 12
xreqLongToStr EQU 13
xreqNumToStr EQU 14
xreqNumToHex EQU 15
xreqBoolToStr EQU 16
xreqExtToStr EQU 17
xreqGetGlobal EQU 18
xreqSetGlobal EQU 19
xreqGetFieldByName EQU 20
xreqGetFieldByNum EQU 21
xreqGetFieldByID EQU 22
xreqSetFieldByName EQU 23
xreqSetFieldByNum EQU 24
xreqSetFieldByID EQU 25
xreqStringEqual EQU 26
xreqReturnToPas EQU 27
xreqScanToReturn EQU 28
xreqScanToZero EQU 39 ; was suppose to be 29! Oops!
; definition of stack frame
stackStor RECORD 0,DECREMENT
stackStorStart EQU *
xcmdBlockAddr DS.L 1
noLock DS.W 1
res DS.W 1
hsize DS.W 1
vsize DS.W 1
i DS.W 1
j DS.W 1
iter DS.W 1
limit DS.W 1
rbaseh DS.W 1
rat DS.L 3
seedh DS.L 3
seedv DS.L 3
valh DS.L 3
valv DS.L 3
temp DS.L 3
basev DS.L 3
baseh DS.L 3
hsq DS.L 3
vsq DS.L 3
real2 DS.L 3
realn2 DS.L 3
real100 DS.L 3
fake256 DS.L 1
fake171 DS.L 1
fake2 DS.L 1
fake100 DS.L 1
r DS.W 4
pats DS.L 8
tempX DS.L 3
tempStr DS.B 256
tempL DS.L 1
stackStorLen EQU *-stackStorStart
ENDR
WITH stackStor
EntryPoint
;;; _Debugger ;
LINK A6,#stackStorLen ;
MOVEM.L A0-A6/D0-D7,-(SP) ;
MOVE.L 8(A6),A3 ;
MOVE.L A3,xcmdBlockAddr(A6) ;
CMPI.W #3,XCmdParamCount(A3) ; if (paramPtr->paramCount<2) return
BLT FracsDone ;
MOVE.L #$00000000,pats(A6) ; pats[0].long1 = 0
MOVE.L #$00000000,pats+4(A6) ; pats[0].long2 = 0
MOVE.L #$AA005500,pats+8(A6) ; pats[1].long1 = 0xaa005500
MOVE.L #$AA005500,pats+12(A6) ; pats[1].long2 = 0xaa005500
MOVE.L #$55FFAAFF,pats+16(A6) ; pats[2].long1 = 0x55ffaaff
MOVE.L #$55FFAAFF,pats+20(A6) ; pats[2].long2 = 0x55ffaaff
MOVE.L #$FFFFFFFF,pats+24(A6) ; pats[3].long1 = 0xffffffff
MOVE.L #$FFFFFFFF,pats+28(A6) ; pats[3].long2 = 0xffffffff
MOVE.W #8,res(A6) ; res = 8
MOVE.W #32,limit(A6) ; limit = 32
MOVE.W #1,nolock(A6) ; nolock = 1
MOVE.L XCmdParams(A3),-(SP) ; seedh = ParamToExt(paramPtr,0)
PEA.L seedh(A6) ;
BSR ZeroToExt ;
ADDQ.L #8,SP ;
MOVE.L XCmdParams+4(A3),-(SP) ; seedv = ParamToExt(paramPtr,1)
PEA.L seedv(A6) ;
BSR ZeroToExt ;
ADDQ.L #8,SP ;
CMPI.W #3,XCmdParamCount(A3) ; if (paramPtr->paramCount>2)
BLT @150 ;
MOVE.L XCmdParams+8(A3),-(SP) ; res = ParamToNum(paramPtr,2)
PEA.L tempL(A6) ;
BSR ZeroToNum ;
ADDQ.L #8,SP ;
MOVE.W tempL+2(A6),res(A6) ;
CMPI.W #0,res(A6) ; if (res <= 0)
BGT.S @110 ;
MOVE.W #1,res(A6) ; res = 1
@110
CMPI.W #4,XCmdParamCount(A3) ; if (paramPtr->paramCount>3)
BLT @150 ;
MOVE.L XCmdParams+12(A3),-(SP) ; limit = ParamToNum(paramPtr,3)
PEA.L tempL(A6) ;
BSR ZeroToNum ;
ADDQ.L #8,SP ;
MOVE.W tempL+2(A6),limit(A6) ;
CMPI.W #3,limit(A6) ; if (limit<4)
BGT.S @120 ;
MOVE.W #4,limit(A6) ; limit = 4
@120
CMPI.W #5,XCmdParamCount(A3) ; if (paramPtr->paramCount>4)
BLT @150 ;
MOVE.L XCmdParams+16(A3),-(SP) ; nolock = !ParamToNum(paramPtr,4)
PEA.L tempL(A6) ;
BSR ZeroToNum ;
ADDQ.L #8,SP ;
MOVE.W tempL+2(A6),nolock(A6) ;
NOT.W nolock(A6) ;
@150
; /* map screen onto -2 to 2 range */
;
; /* 0,0 is at 512/2, 342/2 = 256,171 */
;
; /* gridding to res requires that I find out how many boxes wide and tall
; the image is, and map each box onto a value in r2. then i iterate over
; all the boxes calling the function until the x or y exceeds some limit.
; then i map the number of iterations into a 'color' */
;
; /* since we don't have a global data area for extended constants to live in,
; use longs and fake the compiler into making the correct SANE calls to
; build the extended values. Is there a better way (besides using Pascal!) */
;
MOVE.L #256,fake256(A6) ; fake256 = 256
MOVE.L #171,fake171(A6) ; fake171 = 171
MOVE.L #2,fake2(A6) ; fake2 = 2
MOVE.L #100,fake100(A6) ; fake100 = 100
MOVE.L #256,D0 ; hsize = (fake256/res)+1
DIVS.W res(A6),D0 ;
ADDQ.W #1,D0 ;
MOVE.W D0,hsize(A6) ;
MOVE.L #171,D0 ; vsize = (fake171/res)+1
DIVS.W res(A6),D0 ;
ADDQ.W #1,D0 ;
MOVE.W D0,vsize(A6) ;
FMOVECR.X #$34,FP0 ; real100 = fake100
FMOVE.X FP0,real100(A6) ;
FMOVE.W #2,FP0 ; real2 = fake2
FMOVE.X FP0,real2(A6) ;
FMOVE.W #-2,FP0 ; realn2 = -fake2
FMOVE.X FP0,realn2(A6) ;
FMOVE.X real2(A6),FP0 ; rat = real2/hsize
FDIV.W hsize(A6),FP0 ;
FMOVE.X FP0,rat(A6) ; /* reals intermediate result because of real2 */
MOVE.W res(A6),D0 ; rbaseh = 256-hsize*res
MULS.W hsize(A6),D0 ;
MOVE.W #256,D1 ;
SUB.W D0,D1 ;
MOVE.W D1,rbaseh(A6) ;
MOVE.W res(A6),D0 ; r.top = 171-vsize*res
MULS.W vsize(A6),D0 ;
MOVE.W #171,D1 ;
SUB.W D0,D1 ;
MOVE.W D1,r(A6) ;
ADD.W res(A6),D1 ; r.bottom = r.top + res
MOVE.W D1,r+4(A6) ;
FMOVE.L fake171(A6),FP2 ; basev = realn2*fake171/fake256
FMUL.X realn2(A6),FP2 ; /* center it */
FDIV.L fake256(A6),FP2 ;
FMOVE.X seedv(A6),FP0 ;
FMOVE.X seedh(A6),FP1 ;
; for loop
MOVE.W vsize(A6),D4 ; for (i=-vsize; i<vsize; ++i)
NEG.W D4 ;
@200
CMP.W vsize(A6),D4 ;
BGE @500 ;
MOVE.W rbaseh(A6),D0 ; r.left = rbaseh
MOVE.W D0,r+2(A6) ;
ADD.W res(A6),D0 ; r.right = r.left + res
MOVE.W D0,r+6(A6) ;
FMOVE.X realn2(A6),FP3 ; baseh = realn2
; for loop
MOVE.W hsize(A6),D3 ; for (j=-hsize; j<hsize; ++j)
NEG.W D3 ;
@250
CMP.W hsize(A6),D3 ;
BGE @450 ;
FMOVE.X FP3,FP5 ; valh = baseh
FMOVE.X FP2,FP4 ; valv = basev
CLR.W D5 ; iter = 0
; do loop
@300
;
;
; register assignments to speed up loop
;
; hsq is in FP7
; vsq is in FP6
; valh is in FP5
; valv is in FP4
; baseh is in FP3
; basev is in FP2
; seedh is in FP1
; seedv is in FP0
;
FMOVE.X FP4,FP6 ; vsq = valv * valv
FMUL.X FP4,FP6 ;
FMUL.X FP5,FP4 ; valv = real2*valh*valv + seedv
FADD.X FP4,FP4 ;
FADD.X FP0,FP4 ;
FMUL.X FP5,FP5 ; hsq = valh * valh
FMOVE.X FP5,FP7 ;
FSUB.X FP6,FP5 ; valh = hsq - vsq + seedh
FADD.X FP1,FP5 ;
ADDQ.W #1,D5 ; ++iter
FADD.X FP6,FP7 ; while ((hsq+vsq<real100) && (iter<limit))
FMOVECR.X #$34,FP6 ;
FCMP.X FP7,FP6 ;
FBLE.W @350 ;
CMP.W limit(A6),D5 ;
BLE @300 ;
@350
FADD.X rat(A6),FP3 ; baseh += rat
ANDI.W #3,D5 ; PenPat(&pats[iter & 0x03])
LSL.W #3,D5 ;
LEA.L pats(A6),A0 ;
ADDA.W D5,A0 ;
MOVE.L A0,-(SP) ;
_PenPat ;
PEA.L r(A6) ; PaintRect(&r)
_PaintRect ;
MOVE.W res(A6),D0 ; r.left += res
ADD.W D0,r+2(A6) ;
ADD.W D0,r+6(A6) ; r.right += res
ADDQ.W #1,D3 ;
BRA @250 ;
@450
FADD.X rat(A6),FP2 ; basev += rat
MOVE.W res(A6),D0 ; r.top += res
ADD.W D0,r(A6) ;
ADD.W D0,r+4(A6) ; r.bottom += res
TST.W nolock(A6) ; if (nolock && Button()) return
BEQ.S @475 ;
CLR.W -(SP) ;
_Button ;
TST.W (SP)+ ;
BNE FracsDone ;
@475
ADDQ.W #1,D4 ;
BRA @200 ;
@500
FracsDone
MOVEM.L (SP)+,A0-A6/D0-D7 ; restore registers
UNLK A6
MOVE.L (SP)+,(SP)
RTS
ZeroToNum
MOVE.L xcmdBlockAddr(A6),A3 ; xcmd blk ptr
MOVE.L 8(SP),A0 ; handle to num string
MOVE.L (A0),XCmdInArgs(A3) ; ptr to num string
LEA.L tempStr(A6),A0 ; pt to temp string area
MOVE.L A0,XCmdInArgs+4(A3) ; set temp string ptr
MOVE.W #xreqZeroToPas,XCmdRequest(A3) ; convert to pascal string
MOVE.L XCmdEntryPoint(A3),A0 ; get entry point addr
JSR (A0) ; call HC
LEA.L tempStr(A6),A0 ; pt to temp string area
MOVE.L A0,XCmdInArgs(A3) ; set first arg
MOVE.W #xreqStrToNum,XCmdRequest(A3) ; set req code
MOVE.L XCmdEntryPoint(A3),A0 ; get entry point addr
JSR (A0) ; call HC
MOVE.L 4(SP),A0 ; ptr to result field
MOVE.L XCmdOutArgs(A3),(A0) ; set result
RTS ;
ZeroToExt
MOVE.L xcmdBlockAddr(A6),A3 ; xcmd blk ptr
MOVE.L 8(SP),A0 ; handle to num string
MOVE.L (A0),XCmdInArgs(A3) ; ptr to num string
LEA.L tempStr(A6),A0 ; pt to temp string area
MOVE.L A0,XCmdInArgs+4(A3) ; set temp string ptr
MOVE.W #xreqZeroToPas,XCmdRequest(A3) ; convert to pascal string
MOVE.L XCmdEntryPoint(A3),A0 ; get entry point addr
JSR (A0) ; call HC
LEA.L tempStr(A6),A0 ; pt to temp string area
MOVE.L A0,XCmdInArgs(A3) ; set first arg
LEA.L tempX(A6),A0 ; pt to temp string area
MOVE.L A0,XCmdInArgs+4(A3) ; set first arg
MOVE.W #xreqStrToExt,XCmdRequest(A3) ; set req code
MOVE.L XCmdEntryPoint(A3),A0 ; get entry point addr
JSR (A0) ; call HC
MOVE.L 4(SP),A0 ; ptr to result field
MOVE.W tempX(A6),(A0)+ ; set result
CLR.W (A0)+ ; fill in the zeros
MOVE.L tempX+2(A6),(A0)+ ; set result
MOVE.L tempX+6(A6),(A0)+ ; set result
RTS ;
ENDWITH
ENDMAIN
END